with Ada.Containers.Ordered_Maps;
with Ada.Containers.Bounded_Vectors;
with Legend.Renders;
with Legend.Hero_State_Dialog;
package Legend.Stages.WarFields is

   subtype War_Layer_Type is Layer_Type (0 .. War_Field_Height - 1, 0 .. War_Field_Height - 1);


   type War_Field_Type is new Stage_Type with private;

   procedure Set_Profile (
      this : in out War_Field_Type; 
      Profile : War_Define_Type
      );

   function Get_Winner (
      this : War_Field_Type
      ) return Camp_Type;

   overriding
   procedure Load_Map (this : in out War_Field_Type);

   overriding
   procedure Load_Heroes (this : in out War_Field_Type);

   overriding
   procedure Initialize (this : in out War_Field_Type);

   overriding
   procedure Finalize (this : in out War_Field_Type);

   overriding
   procedure On_Timer (
      this          : in out War_Field_Type;
      Timer         : Hash_Type;
      Count         : Natural;
      Cancel_Bubble : in out Boolean
      );

   overriding
   procedure Run (this : in out War_Field_Type);

   overriding
   procedure Use_Drug_Item (this : in out War_Field_Type; Item : in out Item_Type);

   overriding
   procedure Use_Throw_Item (this : in out War_Field_Type; Item : in out Item_Type);

   type War_Field_Pointer is access all War_Field_Type'Class;

private

   function More_Quick (
      Left, Right : Roles.Role_Pointer
      ) return Boolean;

   package Turns is
      new Roles.Role_Lists.Generic_Sorting(More_Quick);

   type Shadows_Type is record
      Active  : Boolean;
      Picture : Picture_Type;
      Points  : Point_Lists.List;
   end record;

   procedure Generate_Movement_Grids (
      Points  : in out Point_Lists.List;
      Center  : Point_Type;
      Radius  : Int16_t
      );

   procedure Generate_Area_Attack_Grids (
      Points : in out Point_Lists.List;
      Center : Point_Type;
      Radius : Int16_t
      );

   function In_Shadows (
      Point   : Point_Type; 
      Shadows : Shadows_Type
      ) return Boolean;

   type Locator_Type is record
      Active   : Boolean;
      Picture  : Picture_Type;
      Position : Point_Type;
   end record;

   type Effects_Type is record
      Active  : Boolean;
      Movie   : Movie_Type;
      Points  : Point_Lists.List;
   end record;

   type War_Action_Type is (
      wa_Cure,
      wa_Poison,
      wa_Detoxify,
      wa_Kongfu,
      wa_Throw,
      wa_Drug, 
      wa_Rest
      );

   -- 行动方案
   type Action_Plan_Type (Action : War_Action_Type) is record
      Target : Point_Type; -- target position
      Role   : Roles.Role_Pointer;
      case Action is
         when wa_Kongfu =>
            Kongfu  : Uint16_t;
            Level   : Kongfu_Level_Range;
            Index   : Kongfu_Index_Range;
            Face    : Face_Type;
         when wa_Throw =>
            Item    : Uint16_t;
         when wa_Drug  =>
            Drug    : Uint16_t;
         when others =>
            null;
      end case;
   end record;

   subtype Kongfu_Plan_Type is Action_Plan_Type(wa_Kongfu);

   package Kongfu_Plan_Lists is
      new Bounded_Vectors(Positive, Kongfu_Plan_Type); 

   type War_State_Type is record
      Camp       : Camp_Type;
      Steps      : Int16_t;
      Can_Action : Boolean;
      Exp        : Uint16_t;
      Kongfus    : Kongfu_Plan_Lists.Vector(Kongfu_Index_Range'Range_Length);
   end record;

   package Role_State_Maps is
      new Ordered_Maps(Uint16_t, War_State_Type);

   subtype War_State_Ref is Role_State_Maps.Reference_Type;

   type Camp_Knowdges is array(Camp_Type) of Int16_t;

   type War_Field_Type is new Stage_Type with record
      Profile : War_Define_Type;
      Shadows : Shadows_Type;
      Locator : Locator_Type;
      Effects : Effects_Type;
      States  : Role_State_Maps.Map;
      Winner  : Camp_Type;
      Knowdge : Camp_Knowdges; -- 各阵营的武学常识
      Host    : Boolean; -- 是否托管 
      Box     : aliased Hero_State_Dialog.Hero_State_Box_Type;
   end record;

   overriding
   procedure Paint_Surface (
      this : in out War_Field_Type;
      Corners : View_Corners_Type
      );

   overriding
   procedure Paint_Components (this : in out War_Field_Type);

   procedure Reset_Shadows (
      this            : in out War_Field_Type;
      Center          : Point_Type;
      Radius          : Int16_t;
      Enable_Obstacle : Boolean
      );

   function Select_Location (
      this            : in out War_Field_Type;
      Radius          : Int16_t;
      Result          : in out Point_Type;
      Enable_Obstacle : Boolean := True
      ) return Boolean;

   function Select_Attack_Kongfu (
      this : in out War_Field_Type;
      Plan : in out Kongfu_Plan_Type
      ) return Boolean;

   function Select_Attack_Direction (
      this : in out War_Field_Type;
      Face : in out Face_Type
      ) return Boolean;

   function Is_Same_Camp (
      this : War_Field_Type;
      R1, R2 : Roles.Role_Pointer
      ) return Boolean;

   procedure Search_Nearest_Enemy (
      this : in out War_Field_Type;
      Enemy : out Roles.Role_Pointer
      );

   procedure Search_Weakest_Enemy (
      this : in out War_Field_Type;
      Enemy : out Roles.Role_Pointer
      );

   procedure Move_Towards (
      this : in out War_Field_Type;
      Where : Point_Type
      );

   function Next_Turn (this : in out War_Field_Type) return Boolean;

   procedure Init_Turn (
      this : in out War_Field_Type
      );

   procedure End_Turn (
      this : in out War_Field_Type;
      Action : War_Action_Type := wa_Rest
      );

   procedure Delete_Dead_Heroes (this : in out War_Field_Type);

   function Current_Hero_State (
      this : in out War_Field_Type
      ) return Role_State_Maps.Reference_Type;

   procedure On_Player_Turn (this : in out War_Field_Type);

   procedure On_War_Menu_Move (this : in out War_Field_Type);

   procedure On_War_Menu_Cast (this : in out War_Field_Type);

   procedure On_War_Menu_Poison (this : in out War_Field_Type);

   procedure On_War_Menu_Detoxify (this : in out War_Field_Type);

   procedure On_War_Menu_Cure (this : in out War_Field_Type);

   procedure On_War_Menu_Item (this : in out War_Field_Type);

   procedure On_War_Menu_State (this : in out War_Field_Type);

   procedure Auto_Cure (this : in out War_Field_Type);

   procedure Auto_Drug (this : in out War_Field_Type);

   procedure Auto_Attack (this : in out War_Field_Type);

   procedure Auto_Fight (this : in out War_Field_Type);

   procedure Execute_Kongfu_Plan (
      this : in out War_Field_Type;
      Plan : Action_Plan_Type
      ) with Pre => Plan.Action = wa_Kongfu;

   procedure Execute_Throw_Plan (
      this : in out War_Field_Type;
      Plan : Action_Plan_Type
      ) with Pre => Plan.Action = wa_Throw;

   procedure Execute_Cure_Plan (
      this : in out War_Field_Type;
      Plan : Action_Plan_Type
      ) with Pre => Plan.Action = wa_Cure;

   procedure Execute_Poison_Plan (
      this : in out War_Field_Type;
      Plan : Action_Plan_Type
      ) with Pre => Plan.Action = wa_Poison;

   procedure Execute_Detoxify_Plan (
      this : in out War_Field_Type;
      Plan : Action_Plan_Type
      ) with Pre => Plan.Action = wa_Detoxify;

   procedure Execute_Drug_Plan (
      this : in out War_Field_Type;
      Plan : Action_Plan_Type
      ) with Pre => Plan.Action = wa_Drug;

   procedure Execute_Plan (
      this : in out War_Field_Type; 
      Plan : Action_Plan_Type
      );

   procedure Compute_Best_Area_Attack_Point (
      this          : in out War_Field_Type;
      Attacker      : Roles.Role_Pointer;
      Cast_Radius   : Int16_t;
      Damage_Radius : Int16_t;
      Result        : out Point_Type
      );

   function Compute_Area_Hero_Count (
      this : War_Field_Type;
      Area : Point_Lists.List;
      Camp : Camp_Type
      ) return Count_Type;

   procedure Update_Camp_Knowdges (this : in out War_Field_Type);

   procedure Inc_Exp (
      this : in out War_Field_Type;
      Hero : in out Hero_Type;
      Exp  : Uint16_t
      );

   procedure Play_Plan_Movie (
      this   : in out War_Field_Type;
      Kind   : Attack_Kind_Type;     
      Face   : Face_Type;
      Effect : Uint16_t
      );

   overriding
   procedure On_Popup_Menu (
      this : in out War_Field_Type;
      Menubar : in out Menus.Menubar_Pointer
      );

   overriding
   procedure On_Command (
      this : in out War_Field_Type;
      Command : Integer
      );

end Legend.Stages.WarFields;
